博客
关于我
Netty堆外内存泄露排查与总结
阅读量:67 次
发布时间:2019-02-26

本文共 1170 字,大约阅读时间需要 3 分钟。

今天,我遇到了一个让人头疼的问题,Netty框架在运行过程中出现了堆外内存泄露,导致服务端 WebSocket 连接大量出现5xx错误。作为一个刚入行的开发人员,我对这种问题还不太熟悉,于是决定一步步深入排查,找到问题的根源并解决它。

首先,问题开始于Nginx出现大量5xx错误,这通常意味着服务端在处理请求时出现了问题。根据监控平台的日志,我注意到某台机器在同一时间点爆发了GC,并且 JVM 线程被阻塞。这让我怀疑是不是内存问题导致的。

接下来,我查看了日志,发现log4j2在大量打印日志,导致NIO线程被阻塞。这可能是因为log4j2的配置文件中没有正确注释掉控制台打印的日志模块,导致大量日志被同步打印,阻塞了线程。于是,我尝试注释掉这部分日志模块,但问题并没有解决,这让我开始怀疑还有其他隐藏的问题。

然后,我发现日志中出现了大量的failed to allocate 64(bytes) of direct memory错误,这表明堆外内存不足,Netty框架自己封装了一个OutOfDirectMemoryError。这让我意识到可能存在堆外内存泄露的问题,但之前的监控指标显示没有异常,我感到有些困惑。

进一步分析,我注意到Netty在分配堆外内存时使用了PlatformDependent.incrementMemory()方法,发现这是在堆外内存分配时触发的计数器检查。通过检查代码,我发现当堆外内存已使用超过用户指定的上限时,Netty会抛出自定义的OOM错误。这表明堆外内存确实没有被正确释放。

为了监控堆外内存的使用情况,我通过反射获取了DIRECT_MEMORY_COUNTER字段,并在控制台打印内存使用情况。初步发现内存在缓慢增长,随着时间的推移,内存使用量迅速升高,达到几百MB,最后导致OOM爆发。

为了找出内存泄露的具体原因,我在本地环境中模拟了客户端连接和关闭的过程,观察内存变化。发现每次客户端连接断开时,堆外内存会增加一段256B的内存,并且无法释放。这让我怀疑是在断开连接时发生了内存泄露。

通过使用Idea进行线上跟踪,我定位到在onDisconnect事件处理中,Netty框架在某个地方申请了堆外内存但没有正确释放。在进一步的调试中,我发现了一个潜在的NPE异常,发现了subType字段为null的情况,导致内存泄露。

最终,我修改了代码,确保在断开连接时subType字段被正确赋值,避免了NPE异常的发生。随后,我进行了本地和线上的验证,确认问题得到解决。

通过这次排查过程,我学会了如何一步步缩小问题范围,利用调试工具定位内存泄露的根源,并学会了如何通过反射监控堆外内存,确保框架的稳定性。这次经历让我对Netty框架的内存管理有了更深入的理解,也提升了我解决复杂问题的能力。

转载地址:http://aobz.baihongyu.com/

你可能感兴趣的文章
RabbitMQ连接报错(1)—— None of the specified endpoints were reachable
查看>>
php实现逆转数组
查看>>
PHP实现通过geoip获取IP地理信息
查看>>
PHP实现页面静态化、纯静态化及伪静态化
查看>>
php容许ajax跨域,PHP设置允许ajax跨域请求的两种常见方法
查看>>
RabbitMQ进程结构分析与性能调优
查看>>
PHP对接百度地图
查看>>
PHP对表单提交特殊字符的过滤和处理
查看>>
php对象引用和析构函数的关系
查看>>
RabbitMQ HTTP 认证后端项目常见问题解决方案
查看>>
PHP将图片转换成base64格式(优缺点)
查看>>
php将多个值的数组去除重复元素
查看>>
php局域网上传文件_PHP如何通过CURL上传文件
查看>>
PHP工具插件大全
查看>>
php布尔值的++
查看>>
PHP常量、变量作用域详解(一)
查看>>
PHP应用目录结构设计
查看>>
PHP应用程序连接MSQL数据库Demo(附crud程序)
查看>>
PHP应用程序连接Oracle数据库Demo(附Oracle客户端安装文件)
查看>>
PHP开发api接口安全验证
查看>>